package com.sy.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sy.blog.dao.daos.Archives;
import com.sy.blog.dao.mapper.ArticleBodyMapper;
import com.sy.blog.dao.mapper.ArticleMapper;
import com.sy.blog.dao.mapper.ArticleTagMapper;
import com.sy.blog.dao.pojo.Article;
import com.sy.blog.dao.pojo.ArticleBody;
import com.sy.blog.dao.pojo.ArticleTag;
import com.sy.blog.dao.pojo.SysUser;
import com.sy.blog.service.*;
import com.sy.blog.utils.UserThreadLocal;
import com.sy.blog.vo.ArticleBodyVo;
import com.sy.blog.vo.Result;
import com.sy.blog.vo.ArticleVo;
import com.sy.blog.vo.TagVo;
import com.sy.blog.vo.params.ArticleParams;
import com.sy.blog.vo.params.PageParams;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private TagService tagService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private ThreadService threadService;

    @Autowired
    private ArticleTagMapper articleTagMapper;

    /**
     * 根据Page和PageSize分页查询出文章列表
     * @param params
     * @return
     */
    @Override
    public Result listArticle(PageParams params) {

        Page<Article> page = new Page<>(params.getPage(),params.getPageSize());

        IPage<Article> articleIPage = articleMapper.listArticle(
                page,
                params.getCategoryId(),

                params.getTagId(),
                params.getYear(),
                params.getMonth());
        List<Article> records = articleIPage.getRecords();
        return Result.success(copyList(records,true,true));

        /*// 获取分页对象
        Page<Article> page = new Page<>(params.getPage(), params.getPageSize());
        // 条件构造器
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        //查询文章的参数 加上分类id，判断不为空 加上分类条件
        // 也就是说如果有分类id的情况下，就查询对应分类id的文章
        if (params.getCategoryId() != null) {
            queryWrapper.eq(Article::getCategoryId,params.getCategoryId());
        }
        List<Long> articleIdList = new ArrayList<>();
        if (params.getTagId() != null){
            //加入标签 条件查询
            //article表中 并没有tag字段 一篇文章 有多个标签
            //article_tag  article_id 1 : n tag_id
            // 先从article_tag表中根据tag_id查出所有的字段
            // 再遍历所有的数据将对应的标签的文章id全部放到list集合中
            // 然后在通过in给Article表的查询添加新的条件
            LambdaQueryWrapper<ArticleTag> articleTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
            articleTagLambdaQueryWrapper.eq(ArticleTag::getTagId, params.getTagId());
            List<ArticleTag> articleTags = articleTagMapper.selectList(articleTagLambdaQueryWrapper);
            for (ArticleTag articleTag : articleTags) {
                articleIdList.add(articleTag.getArticleId());
            }
            if (articleIdList.size() > 0){
                // and id in(1,2,3)
                queryWrapper.in(Article::getId,articleIdList);
            }
        }

        // 先根据是否置顶排序，再根据创建时间排序
        queryWrapper.orderByDesc(Article::getWeight, Article::getCreateDate);
        Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
        List<Article> records = articlePage.getRecords();
        // 将数据映射对象转换为vo对象后返回（防止映射对象和返回给的前端对象耦合）
        List<ArticleVo> articleVos = copyList(records, true, true);

        // 成功返回data即可
        return Result.success(articleVos);*/

    }

    /**
     * 根据ViewCounts倒序排序，并取其中的前5个
     * last("limit " + limit); limit后面要有空格否则会被拼上去
     * @return
     */
    @Override
    public Result listLatestArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getViewCounts);
        queryWrapper.select(Article::getId, Article::getTitle);
        queryWrapper.last("limit " + limit);
        // select id, title from sy_article order by view_Counts desc limit 5
        List<Article> articles = articleMapper.selectList(queryWrapper);
        return Result.success(copyList(articles, false, false));
    }

    @Override
    public Result listHotArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getCreateDate);
        queryWrapper.select(Article::getId, Article::getTitle);
        queryWrapper.last("limit " + limit);
        // select id, title from sy_article order by view_Counts desc limit 5
        List<Article> articles = articleMapper.selectList(queryWrapper);
        return Result.success(copyList(articles, false, false));
    }

    @Override
    public Result listArchives() {
        List<Archives> archives = articleMapper.listArchives();
        return Result.success(archives);
    }

    /**
     * 根据文章表（article）关联（bodyId和categoryId）
     * 查出文章的详情内容（articleBody）和分类（category）
     * 同时赋值给ArticleVo返回给前端页面
     * private ArticleBodyVo body;
     * private List<CategoryVo> categorys;
     * @return
     */
    @Override
    public Result findArticleById(Long id) {
        Article article = articleMapper.selectById(id);
        ArticleVo articleVo = copy(article, true, true,true,true);
        /**
         * 采用线程池的方式来增加阅读记录，从而防止在更新阅读记录的时候影响
         * 到主线程
         */
        threadService.updateArticleViewCount(articleMapper,article);
        return Result.success(articleVo);
    }

    /**
     * 1、创建文章对象，进行赋值插入
     * 2、标签
     * 3、body
     * @return
     */
    @Override
    public Result publish(ArticleParams articleParams) {
        // 从本地线程变量中获取SysUser对象（接口要添加到拦截器中）
        SysUser sysUser = UserThreadLocal.get();
        Article article = new Article();
        article.setViewCounts(0);
        article.setAuthorId(sysUser.getId());
        article.setCategoryId(Long.parseLong(articleParams.getCategory().getId()));
        article.setCommentCounts(0);
        article.setCreateDate(System.currentTimeMillis());
        article.setSummary(articleParams.getSummary());
        article.setTitle(articleParams.getTitle());
        article.setWeight(Article.Article_Common);
        article.setBodyId(-1L);  // 设置一个默认值，后面进行真实赋值
        // 插入后会生成对应的id
        articleMapper.insert(article);

        // article_tag多表赋值
        for (TagVo tagVo :articleParams.getTags()) {
            ArticleTag articleTag = new ArticleTag();
            articleTag.setTagId(Long.parseLong(tagVo.getId()));
            articleTag.setArticleId(article.getId());
            articleTagMapper.insert(articleTag);
        }

        // article_body表赋值
        ArticleBody articleBody = new ArticleBody();
        articleBody.setContent(articleParams.getBody().getContent());
        articleBody.setContentHtml(articleParams.getBody().getContentHtml());
        articleBody.setArticleId(article.getId());
        articleBodyMapper.insert(articleBody);

        article.setBodyId(articleBody.getId());
        articleMapper.updateById(article);
        ArticleVo articleVo = new ArticleVo();
        articleVo.setId(article.getId().toString());
        return Result.success(articleVo);
    }

    public List<ArticleVo> copyList(List<Article> records, Boolean isTag, Boolean isAuthor) {
        ArrayList<ArticleVo> articleVos = new ArrayList<>();
        for (Article article : records) {
            articleVos.add(copy(article, isTag, isAuthor, false, false));
        }
        return articleVos;
    }

    public List<ArticleVo> copyList(List<Article> records, Boolean isTag, Boolean isAuthor, Boolean isBody, Boolean isCategory) {
        ArrayList<ArticleVo> articleVos = new ArrayList<>();
        for (Article article : records) {
            articleVos.add(copy(article, isTag, isAuthor, isBody, isCategory));
        }
        return articleVos;
    }

    /**
     * 将Article中的值复制到ArticleVo中
     * @param article
     * @return
     */
    public ArticleVo copy(Article article, Boolean isTag, Boolean isAuthor, Boolean isBody, Boolean isCategory) {

        ArticleVo articleVo = new ArticleVo();
        articleVo.setId(String.valueOf(article.getId()));
        BeanUtils.copyProperties(article, articleVo);
        // 此处Vo的创建时间是String而不是Long类型，要转换后单独设置
        articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
        // 判断当前返回给前端的数据是否需要文章标签和作者
        if (isTag) {
            // 获取当前文章的id，用于查询标签
            Long articleId = article.getId();  // 文章id
            articleVo.setTags(tagService.findTagsByArticleId(articleId));
        }

        if (isAuthor) {
            // 获取当前文章的作者id，用于查询作者信息在查出作者名字
            Long authorId = article.getAuthorId();
            articleVo.setAuthor(sysUserService.findUserByArticleId(authorId).getNickname());
        }

        if (isBody) {
            // 获取当前文章的内容id，查询出文章的具体内容
            Long bodyId = article.getBodyId();
            articleVo.setBody(findArticleBodyById(bodyId));
        }

        if (isCategory) {
            // 获取当前文章的分类id，查询出该文章的分类信息
            Long categoryId = article.getCategoryId();
            articleVo.setCategory(categoryService.findCategoryById(categoryId));
        }

        return articleVo;
    }

    @Autowired
    private ArticleBodyMapper articleBodyMapper;

    private ArticleBodyVo findArticleBodyById(Long bodyId) {

        ArticleBody articleBody = articleBodyMapper.selectById(bodyId);
        ArticleBodyVo articleBodyVo = new ArticleBodyVo();
        articleBodyVo.setContent(articleBody.getContent());

        return articleBodyVo;
    }
}
